﻿namespace MicroCloud.AspNetCore.Mvc.ModelBinding
{
    /// <summary>
    /// 提供对字符串前后空白进行Trim操作的模型绑定能力
    /// </summary>
    public class StringTrimModelBinder : IModelBinder
    {
        /// <summary>
        /// 尝试绑定模型
        /// </summary>
        /// <param name="bindingContext">The <see cref="ModelBindingContext" /></param>
        /// <returns>
        /// <para>
        /// 一个<see cref="Task" />模型绑定过程完成时完成。
        /// </para>
        /// <para>
        /// 如果模型绑定成功，则 <see cref="ModelBindingContext.Result" /> 应具备<see cref="ModelBindingResult.IsModelSet" /> 设置为 <c>true</c>.
        /// </para>
        /// <para>
        /// 应设置成功完成的模型绑定器 <see cref="ModelBindingContext.Result" /> 为
        /// 成功返回的值 <see cref="ModelBindingResult.Success(Object)" />.
        /// </para>
        /// </returns>
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            Check.NotNull(bindingContext, nameof(bindingContext));

            ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (valueProviderResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }
            Type underlyingOrModelType = bindingContext.ModelMetadata.UnderlyingOrModelType;
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

            try
            {
                string firstValue = valueProviderResult.FirstValue;
                object model;
                if (string.IsNullOrWhiteSpace(firstValue))
                {
                    model = null;
                }
                else
                {
                    if (underlyingOrModelType != typeof(string))
                    {
                        throw new MulticastNotSupportedException();
                    }
                    model = firstValue.Trim();
                }
                bindingContext.Result = ModelBindingResult.Success(model);
                return Task.CompletedTask;
            }
            catch (System.Exception ex)
            {
                System.Exception exception = ex;
                if (exception is not FormatException && exception.InnerException != null)
                {
                    exception = ExceptionDispatchInfo.Capture(exception.InnerException).SourceException;
                }
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, exception, bindingContext.ModelMetadata);
                return Task.CompletedTask;
            }
        }
    }
}
